pub mod agent;
mod sess_loop;
mod cacher;

use rust_fsm::*;
use crate::configs::AgentConf;
use crate::upstream::agent::Agent;
use crate::upstream::sess_loop::loop_process;

/*
 * 数据上报通信状态机
 */
state_machine! {
    derive(Debug)
    repr_c(true)
    CloudCommu(Closed)

    // 关闭状态, Event开始, 进入Init状态
    Closed(Start) => Init [OK],
    // 初始化状态, Event成功, 进入Login状态
    Init(Successful) => Login,
    Login => {
        // Event登陆成功,进入Loop正常循环状态
        Successful => Loop,
        // Event登陆返回失败,重新进入Login状态
        Unsuccessful => Login [LoginFailed],
    },
    // 循环状态
    Loop => {
        // loop过程中,遇到poweroff, 进入到shutdown
        PowerOff => Shutdown,
        // loop返回,返回login,重新登陆
        Unsuccessful => Login [ConnFailed],
    },
    // 关机状态,执行相关操作,例如断电前数据保存
    Shutdown => {
        // Event Done,表示关机完成,进入closed状态
        Done => Closed [ProcessOver]
    },
}


pub async fn serv_run(agent_cfg: &AgentConf) {

    // 客户度登陆尝试的次数
    let mut try_seed: u16 = 0;
    let mut cloud_fsm: StateMachine<CloudCommu> = StateMachine::new();
    let mut fsm_output = Some(CloudCommuOutput::OK);
    let mut agent_ins = Agent::build(agent_cfg);
    loop {
        match cloud_fsm.state() {
            CloudCommuState::Closed => {
                if let Some(CloudCommuOutput::OK) = fsm_output {
                    let _ = cloud_fsm.consume(&CloudCommuInput::Start);
                    log::info!("Upstream transaction Closed -> Init");
                }
            }
            CloudCommuState::Init => {
                // TODO: 初始化各种,包括外设等
                let _ = cloud_fsm.consume(&CloudCommuInput::Successful);
                log::info!("Upstream transaction Init -> Login");
                // TODO: 打印,led闪灯等等
            }
            CloudCommuState::Login => {
                // 登录状态
                log::info!("Upstream try to login");
                let mut wait_now = false;
                match fsm_output.unwrap() {
                    CloudCommuOutput::ConnFailed => {
                        // 表示连接失败
                        try_seed = 0;
                        wait_now = true;
                    }
                    CloudCommuOutput::LoginFailed => {
                        try_seed = try_seed.wrapping_add(1);
                    }
                    CloudCommuOutput::OK => {
                        try_seed = 0;
                    }
                    _ => {
                        try_seed = 0;
                    }
                }

                let reg_ret = agent_ins.register(agent_cfg, try_seed, wait_now).await;
                if reg_ret.is_err() {
                    log::warn!("Upstream login failed {:?}", reg_ret);
                    fsm_output = cloud_fsm.consume(&CloudCommuInput::Unsuccessful).unwrap();
                } else {
                    log::info!("Upstream login done");
                    fsm_output = Some(CloudCommuOutput::OK);
                    try_seed = 0;
                    let _ = cloud_fsm.consume(&CloudCommuInput::Successful);
                }
            }
            CloudCommuState::Loop => {
                log::info!("Upstream Loop start");
                let loop_ret = loop_process(&mut agent_ins, agent_cfg).await;
                if loop_ret.is_err() {
                    log::warn!("Upstream loop process failed");
                    fsm_output = cloud_fsm.consume(&CloudCommuInput::Unsuccessful).unwrap();
                }
                // 正常退出
                let _ = cloud_fsm.consume(&CloudCommuInput::PowerOff);
            }
            CloudCommuState::Shutdown => {
                log::info!("Upstream Shutdown start");
                // TODO: 调用 关闭电源前的各种保存工作.etc
                fsm_output = cloud_fsm.consume(&CloudCommuInput::Done).unwrap();
            }
        }
    }
}